﻿using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace net.xBei.Network {
    /// <summary>
    /// 下载器基于 System.Net.Http.HttpClient
    /// </summary>
    public class Downloader {
        private readonly HttpClient _client;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="client"></param>
        public Downloader(HttpClient client) {
            _client = client;
        }

        private readonly Regex FILENAME_REG = new("filename=(.+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="urlToDownload"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<FileData> DownloadStreamAsync(string urlToDownload, CancellationToken? cancellationToken = default) {
            string? tmpFileName = default;
            string? ContentType = default;
            var res = await _client.GetAsync(urlToDownload, HttpCompletionOption.ResponseHeadersRead);
            var headers = res.Content.Headers;
            if (headers.TryGetValues("Content-Type", out var valuesContentType)) {
                ContentType = valuesContentType.FirstOrDefault();
            }
            // Console.WriteLine(headers.ToList().ToJson(true));
            if (headers.TryGetValues("Content-Disposition", out var values)) {
                var value = values.Where(v => v.Contains("filename=", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                if (!string.IsNullOrWhiteSpace(value) && FILENAME_REG.IsMatch(value)) {
                    var m = FILENAME_REG.Match(value);
                    tmpFileName = m.Groups[1].Value;
                }
            }
            var stream = cancellationToken.HasValue
                            ? await res.Content.ReadAsStreamAsync(cancellationToken.Value)
                            : await res.Content.ReadAsStreamAsync();
            return new FileData {
                Data = stream,
                FileName = tmpFileName,
                ContentType = ContentType,
            };
        }
        /// <summary>
        /// 
        /// </summary>
        public struct FileData {
            /// <summary>
            /// 
            /// </summary>
            public Stream Data { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string? FileName { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string? ContentType { get; set; }
        }
    }
}
